package com.fuhailiu.opengl.utils;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import com.fuhailiu.opengl.define.MSize;

public class ArrayUtil {

	private static final String TAG = ArrayUtil.class.getSimpleName();

	private static final double EXP = 10E-10;

	public static <T> boolean equals(T value1, T value2) {
		if (null == value1 && null == value2) {
			return true;
		}
		if (null == value1 || null == value2) {
			return false;
		}

		if (value1 instanceof Byte) {
			return ((Byte) value1).byteValue() == ((Byte) value2).byteValue();
		} else if (value1 instanceof Short) {
			return ((Short) value1).shortValue() == ((Short) value2).shortValue();
		} else if (value1 instanceof Integer) {
			return ((Integer) value1).intValue() == ((Integer) value2).intValue();
		} else if (value1 instanceof Long) {
			return ((Long) value1).longValue() == ((Long) value2).longValue();
		} else if (value1 instanceof Float) {
			float diff = Math.abs(((Float) value1).floatValue() - ((Float) value2).floatValue());
			return diff > -1 * EXP && diff < EXP;
		} else if (value1 instanceof Double) {
			double diff = Math.abs(((Double) value1).doubleValue() - ((Double) value2).doubleValue());
			return diff > -1 * EXP && diff < EXP;
		} else if (value1 instanceof MSize) {
			return ((MSize) value1).equals(((MSize) value2));
		} else {
			return value1.equals(value2);
		}
	}

	public static <T> boolean hasElementInArray(T[] array, T value) {
		boolean res = false;
		if (null != array && array.length > 0) {
			for (T element : array) {
				if (equals(element, value)) {
					res = true;
					break;
				}
			}
		}
		return res;
	}

	public static boolean hasElementInArray(int[] array, int value) {
		boolean res = false;
		if (null != array && array.length > 0) {
			for (int element : array) {
				if (element == value) {
					res = true;
					break;
				}
			}
		}
		return res;
	}

	/**
	 * 移除重复的元素
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] removeRedundantElement(T[] array, Class<T> type) {
		Set<T> set = new HashSet<T>();
		for (T element : array) {
			set.add(element);
		}
		T[] result = (T[]) Array.newInstance(type, set.size());
		return set.toArray(result);
	}

	/**
	 * 移除数组中指定的元素（可能有多个）
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] removeArrayElementsByValue(T[] array, T value, Class<T> type) {
		if (!hasElementInArray(array, value)) {
			return array;
		}

		int len = array.length;
		if (len == 1) {
			if (array[0] == value) {
				return (T[]) Array.newInstance(type, 0);
			} else {
				return array;
			}
		}

		int[] indices = getIndices(array, value);
		if (null == indices || indices.length <= 0) {
			return array;
		} else {
			int idxLen = indices.length;
			T[] result = (T[]) Array.newInstance(type, len - idxLen);
			int index = 0;
			for (int i = 0; i < len; i++) {
				if (!hasElementInArray(indices, i)) {
					result[index] = array[i];
					index++;
				}
			}
			return result;
		}
	}

	public static <T> int getIndex(T[] array, T value) {
		if (null == array) {
			LogUtil.LogE(TAG, "array is null");
			return -1;
		}

		int index = -1;
		int len = array.length;
		boolean bFound = false;

		for (int i = 0; i < len; i++) {
			T item = array[i];
			bFound = equals(value, item);
			if (bFound) {
				index = i;
				break;
			}
		}

		return index;
	}

	public static <T> int[] getIndices(T[] array, T value) {
		if (!hasElementInArray(array, value)) {
			return null;
		}

		int len = array.length;
		int[] temp = new int[len];
		int index = 0;

		for (int i = 0; i < len; i++) {
			if (equals(array[i], value)) {
				temp[index] = i;
				index++;
			}
		}

		if (0 == index) {
			return null;
		} else {
			int[] result = new int[index];
			System.arraycopy(temp, 0, result, 0, index);
			return result;
		}
	}

	/**
	 * 对数组进行“上升”排序
	 */
	public static <T> void sort(T[] array) {
		Arrays.sort(array);
	}

	/**
	 * 选择排序
	 */
	public static int[] selectSort(int[] array) {
		if (null == array || array.length <= 1) {
			return array;
		}

		int len = array.length;
		for (int i = 0; i < len - 1; i++) {
			int min = i;
			for (int j = i + 1; j < len; j++) {
				if (array[min] > array[j]) {
					min = j;
				}
			}
			if (min != i) {
				int temp = array[i];
				array[i] = array[min];
				array[min] = temp;
			}
		}
		return array;
	}

	/**
	 * 对数组进行反序
	 */
	public static <T> void reverse(T[] array) {
		if (null == array || array.length == 0 || array.length == 1) {
			return;
		}
		int len = array.length;
		int half = len / 2;
		for (int i = 0; i < half; i++) {
			T temp = array[i];
			array[i] = array[len - i - 1];
			array[len - i - 1] = temp;
		}
	}

	public static <T> T[] mergeAll(T[] first, T[]... rest) {
		int totalLength = first.length;
		for (T[] array : rest) {
			totalLength += array.length;
		}
		T[] result = Arrays.copyOf(first, totalLength);
		int offset = first.length;
		for (T[] array : rest) {
			System.arraycopy(array, 0, result, offset, array.length);
			offset += array.length;
		}
		return result;
	}

	public static <T> String array2String(T[] array) {
		return Arrays.toString(array);
	}

}
